#include <klib.h>
#include <klib-macros.h>
#include <stdint.h>

#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)

size_t strlen(const char *s)
{
  size_t length = 0;
  char *ch = (char *)s;
  for (; (*ch) != '\0'; ch++)
  {
    length++;
  }
  return length;
}

char *strcpy(char *dst, const char *src)
{
  char *dch = (char *)dst;
  char *sch = (char *)src;
  size_t length = strlen(src);
  while (length)
  {
    length--;
    *dch++ = *sch++;
  }
  *dch = '\0';
  return dst;
}

char *strncpy(char *dst, const char *src, size_t n)
{
  char *dch = (char *)dst;
  char *sch = (char *)src;
  while (n)
  {
    n--;
    *dch++ = *sch++;
  }
  return dst;
}

char *strcat(char *dst, const char *src)
{
  strcpy(dst + strlen(dst), src);
  return dst;
}

int strcmp(const char *s1, const char *s2)
{
  char *str1 = (char *)s1;
  char *str2 = (char *)s2;
  char ch1, ch2;
  ch1 = *str1, ch2 = *str2;
  while (ch1 == ch2 && ch1 != '\0' && ch2 != '\0')
  {
    ch1 = *(++str1);
    ch2 = *(++str2);
  }
  return ch1 - ch2;
}

int strncmp(const char *s1, const char *s2, size_t n)
{
  if (n == 0)
    return 0;
  char *str1 = (char *)s1;
  char *str2 = (char *)s2;
  char ch1, ch2;
  ch1 = *str1, ch2 = *str2;
  while (ch1 == ch2 && ch1 != '\0' && ch2 != '\0' && n--)
  {
    ch1 = *(++str1);
    ch2 = *(++str2);
  }
  return ch1 - ch2;
}

void *memset(void *s, int c, size_t n)
{
  unsigned char uc = (unsigned char)c;
  unsigned char *sp = (unsigned char *)s;
  while (n--)
  {
    *sp++ = uc;
  }
  return s;
}

void *memmove(void *dst, const void *src, size_t n)
{
  if (dst < src)
  {
    uint32_t *dstd = (uint32_t *)dst;
    uint32_t *srcd = (uint32_t *)src;
    while (n >= 4)
    {
      *dstd++ = *srcd++;
      n -= sizeof(uint32_t);
    }
    uint8_t *dst8d = (uint8_t *)dstd;
    uint8_t *src8d = (uint8_t *)srcd;
    while (n > 0)
    {
      *dst8d++ = *src8d++;
      n -= sizeof(uint8_t);
    }
  }
  else if (dst > src)
  {
    uint8_t *dst8d = ((uint8_t *)dst) + n ;
    uint8_t *src8d = ((uint8_t *)src) + n ;

    while (n > 0 && (n & 0x3 ))
    {
      *--dst8d = *--src8d;
      n -= sizeof(uint8_t);
    }
    uint32_t *dstd = (uint32_t *)dst8d;
    uint32_t *srcd = (uint32_t *)src8d;
    while (n>0)
    {
      *--dstd = *--srcd;
      n -= sizeof(uint32_t);
    }
  }

  return dst;
}

void *memcpy(void *out, const void *in, size_t n)
{
  uint32_t *outd = (uint32_t *)out;
  uint32_t *ind = (uint32_t *)in;
  while (n >= 4)
  {
    *outd++ = *ind++;
    n -= sizeof(uint32_t);
  }
  uint8_t *och = (uint8_t *)outd;
  uint8_t *ich = (uint8_t *)ind;
  while (n)
  {
    *och++ = *ich++;
    n--;
  }
  return out;
}

int memcmp(const void *s1, const void *s2, size_t n)
{
  uint32_t *sd1 = (uint32_t *)s1;
  uint32_t *sd2 = (uint32_t *)s2;
  uint32_t data1 = 0, data2 = 0;
  if (n >= 4)
  {
    do
    {
      data1 = *sd1++;
      data2 = *sd2++;
      n -= sizeof(uint32_t);
    } while (data1 == data2 && n > 4);
  }
  if (data1 == data2 && n)
  {
    uint8_t *sd8_1 = (uint8_t *)sd1;
    uint8_t *sd8_2 = (uint8_t *)sd2;
    uint8_t data8_1, data8_2;
    do
    {
      data8_1 = *sd8_1++;
      data8_2 = *sd8_2++;
      n--;
    } while (data8_1 == data8_2 && n);
    data1 = (uint32_t)data8_1;
    data2 = (uint32_t)data8_2;
  }
  return data1 - data2;
}
// ych
#endif
